﻿using System;
using System.ComponentModel;
using System.Drawing;
using System.Xml.Serialization;
using Microsoft.WowAddonStudio.FrameXml.Serialization.Attributes;
using Microsoft.WowAddonStudio.FrameXml.Serialization.Enumerations;
using Microsoft.WowAddonStudio.FrameXml.Serialization.LayoutFrames;

namespace Microsoft.WowAddonStudio.FrameXml.Serialization
{
    /// <summary>
    /// Represents a font that can be used by <see cref="FontString"/>s and other FrameXML elements.
    /// </summary>
    [Serializable]
    [DesignerCategory("code")]
    [XmlType(Namespace = "http://www.blizzard.com/wow/ui/")]
    [XmlRoot(Namespace = "http://www.blizzard.com/wow/ui/", IsNullable = false)]
    [TypeConverter(typeof (ExpandableObjectConverter))]
    public class Font : InheritableObject
    {
        /// <summary>
        /// Gets or sets the path to the true-type font used by this font.
        /// </summary>
        [XmlAttribute("font")]
        [File(FileType.Font)]
        [Category("Appearance")]
        [Description("The font used to display the text.")]
        [DisplayName("Font")]
        public string TrueTypeFont
        {
            get { return Properties.GetValue<string>("Font"); }
            set { Properties.SetValue("Font", value); }
        }

        /// <summary>
        /// Gets or sets the spacing between the characters of the font. The default is zero.
        /// </summary>
        [XmlAttribute("spacing")]
        [Category("Appearance")]
        [DefaultValue(typeof (float), "0")]
        [Description("The spacing between the charactes of the fontstring.")]
        public float Spacing
        {
            get { return Properties.GetValue<float>("Spacing"); }
            set { Properties.SetValue("Spacing", value); }
        }

        /// <summary>
        /// Gets or sets the type of <see cref="Outline"/> for this font. The default is none.
        /// </summary>
        [XmlAttribute("outline")]
        [Category("Appearance")]
        [DefaultValue(Outline.None)]
        [Description("The outline of the fontstring.")]
        public Outline Outline
        {
            get { return Properties.GetValue<Outline>("Outline"); }
            set { Properties.SetValue("Outline", value); }
        }

        /// <summary>
        /// Gets or sets a value indicating whether this font is monochrome. The default is false.
        /// </summary>
        [XmlAttribute("monochrome")]
        [Category("Appearance")]
        [DefaultValue(false)]
        [Description("The value indicating whether the fontstring is monochrome.")]
        public bool Monochrome
        {
            get { return Properties.GetValue<bool>("Monochrome"); }
            set { Properties.SetValue("Monochrome", value); }
        }

        /// <summary>
        /// Gets or sets the vertical justification of the font. The default is middle.
        /// </summary>
        [XmlAttribute("justifyV")]
        [Category("Appearance")]
        [DefaultValue(JustifyVertical.Middle)]
        [Description("Align text \"TOP\", \"BOTTOM\", or \"MIDDLE\".")]
        public JustifyVertical JustifyVertical
        {
            get { return Properties.GetValue<JustifyVertical>("JustifyVertical"); }
            set { Properties.SetValue("JustifyVertical", value); }
        }

        /// <summary>
        /// Gets or sets the horizontal justification of the font. The default is center.
        /// </summary>
        [XmlAttribute("justifyH")]
        [Category("Appearance")]
        [DefaultValue(JustifyHorizontal.Center)]
        [Description("Align text \"LEFT\", \"RIGHT\", or \"CENTER\".")]
        public JustifyHorizontal JustifyHorizontal
        {
            get { return Properties.GetValue<JustifyHorizontal>("JustifyHorizontal"); }
            set { Properties.SetValue("JustifyHorizontal", value); }
        }

        /// <summary>
        /// Gets or sets the color of the font.
        /// </summary>
        [XmlElement]
        [Color]
        [EditorBrowsable]
        [Category("Appearance")]
        [Description("The color used to display text.")]
        public Color Color
        {
            get { return Properties.GetValue<Color>("Color"); }
            set { Properties.SetValue("Color", value); }
        }

        /// <summary>
        /// Gets or sets the height of the font.
        /// </summary>
        /// <value>The height of the font.</value>
        [XmlElement]
        [Browsable(true)]
        [Category("Appearance")]
        [Description("The FontHeight of the fontstring.")]
        public FontHeight FontHeight
        {
            get { return Properties.GetValue<FontHeight>("FontHeight"); }
            set { Properties.SetValue("FontHeight", value); }
        }

        /// <summary>
        /// Gets or sets the <see cref="Shadow"/> used with the font.
        /// </summary>
        [XmlElement]
        [Shadow]
        [EditorBrowsable]
        [Category("Appearance")]
        [NotifyParentProperty(true)]
        [Description("Puts a shadow behind an element.")]
        public Shadow Shadow
        {
            get { return Properties.GetValue<Shadow>("Shadow"); }
            set { Properties.SetValue("Shadow", value); }
        }

        /// <summary>
        /// Gets the vertical and horizontal alignment of the fontstring as a <see cref="StringFormat"/>.
        /// </summary>
        [XmlIgnore]
        [Browsable(false)]
        public StringFormat StringFormat
        {
            get
            {
                var stringFormat = new StringFormat();

                switch (JustifyVertical)
                {
                    case JustifyVertical.Top:
                        stringFormat.Alignment = StringAlignment.Near;
                        break;
                    case JustifyVertical.Middle:
                        stringFormat.Alignment = StringAlignment.Center;
                        break;
                    case JustifyVertical.Bottom:
                        stringFormat.Alignment = StringAlignment.Far;
                        break;
                }

                switch (JustifyHorizontal)
                {
                    case JustifyHorizontal.Left:
                        stringFormat.Alignment = StringAlignment.Near;
                        break;
                    case JustifyHorizontal.Center:
                        stringFormat.Alignment = StringAlignment.Center;
                        break;
                    case JustifyHorizontal.Right:
                        stringFormat.Alignment = StringAlignment.Far;
                        break;
                }

                return stringFormat;
            }
        }

        /// <summary>
        /// Gets a value indicating whether the fontstring is complete.
        /// </summary>
        [XmlIgnore]
        [Browsable(false)]
        public override bool IsComplete
        {
            get
            {
                return !String.IsNullOrEmpty(TrueTypeFont) &&
                       FontHeight != null && FontHeight.IsComplete &&
                       Color != null;
            }
        }

        /// <summary>
        /// Determines whether this instance [can be inherited from] the specified inheritable object type.
        /// </summary>
        /// <param name="inheritableObjectType">Type of the inheritable object.</param>
        /// <returns>
        /// 	<c>true</c> if this instance [can be inherited from] the specified inheritable object type; otherwise, <c>false</c>.
        /// </returns>
        public override bool CanBeInheritedFrom(Type inheritableObjectType)
        {
            return inheritableObjectType == typeof (FontString) ||
                   inheritableObjectType == typeof (Font);
        }

        /// <summary>
        /// Returns a <see cref="T:System.String"/> that represents the current <see cref="T:System.Object"/>.
        /// </summary>
        /// <returns>
        /// A <see cref="T:System.String"/> that represents the current <see cref="T:System.Object"/>.
        /// </returns>
        public override string ToString()
        {
            if (!String.IsNullOrEmpty(TrueTypeFont))
                return TrueTypeFont;

            return "{Font}";
        }
    }
}